#include "classes.h"

Operand* o_assign;
Operand* o_plus;
Operand* o_clk;
Operand* o_rst;
Operand* o_counter;
Operand* o_neg;

Operand* o_posedge;
Operand* o_const_10_0;
Operand* o_const_10_1;
Operand* o_const_1_0;
Operand* o_const_1_1;

OpTreeNode* v_posedge_clk;
OpTreeNode* v_plus;
OpTreeNode* v_no_rst;
OpTreeNode* v_counter;
OpTreeNode* v_set_count;
OpTreeNode* v_update_count;
OpTreeNode* v_rst_rst;
OpTreeNode* v_neg_clk;
OpTreeNode* v_ass_clk;

Condition* cond_pos_clk;
Condition* cond_rst_n;
Condition* cond_not_rst_n;

Line* l_always;	// always @ (posedge clk)
Line* l1;		//		if (rst_n) counter <= 10'b0;
Line* l2;		//		else counter <= counter + 10'b1;
Line* l3;		// #50 rst_n = 1'b1
Line* l4;		// #5 clk = ~clk

vector<Line*> *vect_child;

vector<Line*> *lines;
vector<Operand*> *operands;

Engine* engine;

void Init()
{
	o_clk = new Operand(OPERAND_REG, 0, "clk");
	o_assign = new Operand(OPERAND_ASSIGN, MAX32, "=");
	o_rst = new Operand(OPERAND_REG, 0, "rst_n");
	o_plus = new Operand(OPERAND_PLUS, MAX32, "+");
	o_counter = new Operand(OPERAND_REG, 0, "counter");
	o_posedge = new Operand(OPERAND_POSEDGE, MAX32, "posedge");
	o_neg = new Operand(OPERAND_NEG, MAX32, "~");
	o_const_10_0 = new Operand(OPERAND_CONST, 0, "10'b0");
	o_const_10_1 = new Operand(OPERAND_CONST, 1, "10'b1");	
	o_const_1_0 = new Operand(OPERAND_CONST, 0, "1'b0");
	o_const_1_1 = new Operand(OPERAND_CONST, 1, "1'b1");	

	v_no_rst = new OpTreeNode(o_neg, (OpTreeNode*) NULL, o_rst); //~rst

	cond_rst_n = new Condition(o_rst); // if(rst)
	cond_not_rst_n = new Condition(v_no_rst); // if(~rst)
	
	// counter <= 10'b0
	v_set_count = new OpTreeNode(o_assign, o_counter, o_const_10_0);

	// if (rst) counter <= 10'b0
	l1 = new Line(NULL, LINE_ASSIGN, cond_rst_n, LINE_EVERY_CYCLE, 0, v_set_count);

	// counter + 10'b1
	v_plus = new OpTreeNode(o_plus, o_counter, o_const_10_1);

	// if(~rst) counter = counter + 10'b1
	v_update_count = new OpTreeNode(o_assign, o_counter, v_plus);

	// else counter = counter + 10'b1
	l2 = new Line(NULL, LINE_ASSIGN, cond_not_rst_n, LINE_EVERY_CYCLE, 0, v_update_count);

	// posedge clk
	v_posedge_clk = new OpTreeNode(o_posedge, (OpTreeNode* ) NULL, o_clk);
	
	// posedge clk
	cond_pos_clk = new Condition(v_posedge_clk);

	vect_child = new vector<Line*>;
	vect_child->push_back(l1);
	vect_child->push_back(l2);

	// always @ posedge clk
	l_always = new Line( vect_child, LINE_ALWAYS, cond_pos_clk, LINE_EVERY_CYCLE, 0, v_posedge_clk);

	// rst <= 1b'1
	v_rst_rst = new OpTreeNode(o_assign, o_rst, o_const_1_1);

	// #50 rst <= 1b'1
	l3 = new Line( NULL, LINE_ASSIGN, NULL, LINE_PERIODICALLY, 50, v_rst_rst);

	// ~clk
	v_neg_clk = new OpTreeNode(o_neg, (OpTreeNode*) NULL, o_clk);
	
	// clk = ~clk 
	v_ass_clk = new OpTreeNode(o_assign, o_clk, v_neg_clk);
	
	// #5 clk = ~clk
	l4 = new Line( NULL, LINE_ASSIGN, NULL, LINE_PERIODICALLY, 5, v_ass_clk);

	
	lines = new vector<Line*>;
	operands = new vector<Operand*>;
	
	operands->push_back(o_clk);
	operands->push_back(o_rst);
	operands->push_back(o_counter);

	lines->push_back(l3);
	lines->push_back(l4);
	lines->push_back(l_always);
	
	engine = new Engine(lines, operands, MAX_CLOCK);
}

int main()
{
	Init();
	
	engine->Simulate();

	return 0;
}
